package com.ruoyi.activiti.utils;

import org.activiti.bpmn.model.*;
import org.activiti.engine.RepositoryService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class ExpressionKeyExtractor {

    @Autowired
    private final RepositoryService repositoryService;
    // 匹配变量表达式：${var}、${var.prop}、${var['prop']}、${map[key]} 等
    private static final Pattern VAR_PATTERN = Pattern.compile(
        "\\$\\{([^{}]+?)}|#\\{([^{}]+?)}"
    );
    // 匹配变量名：排除运算符、方法调用等
    private static final Pattern VALID_VAR_PATTERN = Pattern.compile(
        "^[a-zA-Z_\\$][\\w\\.\\[\\]'\"\\$]*$"
    );
    // UEL 关键字和运算符
    private static final Set<String> UEL_KEYWORDS = new HashSet<>(Arrays.asList(
        "true", "false", "null", "empty", "and", "or", "not", "eq", "ne", "lt", 
        "gt", "le", "ge", "div", "mod", "instanceof", "new"
    ));

    public ExpressionKeyExtractor(RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    /**
     * 提取网关条件表达式中的所有变量键
     * @param processDefinitionId 流程定义ID
     * @param gatewayId 网关ID
     * @return 所有表达式中的变量键（去重）
     */
    public Set<String> extractVariableKeys(String processDefinitionId, String gatewayId) {
        Set<String> allKeys = new HashSet<>();
        List<SequenceFlow> flows = getGatewayOutgoingFlows(processDefinitionId, gatewayId);
        
        for (SequenceFlow flow : flows) {
            if (flow.getConditionExpression() != null) {
                String expression = flow.getConditionExpression();
                Set<String> keys = extractKeysFromExpression(expression);
                allKeys.addAll(keys);
            }
        }
        
        return allKeys;
    }

    /**
     * 提取网关条件表达式中的变量键（按序列流分组）
     * @param processDefinitionId 流程定义ID
     * @param gatewayId 网关ID
     * @return 序列流ID到变量键集合的映射
     */
    public Map<String, Set<String>> extractVariableKeysByFlow(String processDefinitionId, String gatewayId) {
        Map<String, Set<String>> flowKeys = new HashMap<>();
        List<SequenceFlow> flows = getGatewayOutgoingFlows(processDefinitionId, gatewayId);
        
        for (SequenceFlow flow : flows) {
            Set<String> keys = new HashSet<>();
            if (flow.getConditionExpression() != null) {
                keys = extractKeysFromExpression(flow.getConditionExpression());
            }
            flowKeys.put(flow.getId(), keys);
        }
        
        return flowKeys;
    }

    /**
     * 从单个表达式中提取变量键
     * @param expression UEL表达式
     * @return 变量键集合
     */
    public Set<String> extractKeysFromExpression(String expression) {
        Set<String> keys = new HashSet<>();
        if (StringUtils.isBlank(expression)) {
            return keys;
        }
        
        // 匹配所有 ${...} 和 #{...} 模式
        Matcher matcher = VAR_PATTERN.matcher(expression);
        while (matcher.find()) {
            String fullMatch = matcher.group(0); // 整个匹配项 ${var}
            String content = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
            
            // 提取有效变量键
            extractKeysFromContent(content, keys);
        }
        
        return keys;
    }

    /**
     * 从表达式内容中提取变量键
     * @param content 表达式内容（去掉了 ${} 包装）
     * @param keys 存储提取到的变量键
     */
    private void extractKeysFromContent(String content, Set<String> keys) {
        // 按运算符拆分表达式
        String[] parts = content.split("\\s*[+\\-*/%&|^~!=<>?:]\\s*|\\(|\\)|\\s+");
        
        for (String part : parts) {
            String trimmed = part.trim();
            if (isValidVariableKey(trimmed)) {
                // 处理嵌套属性（如 order.price）
                String rootKey = extractRootVariable(trimmed);
                if (!UEL_KEYWORDS.contains(rootKey)) {
                    keys.add(rootKey);
                }
            }
        }
    }

    /**
     * 验证是否为有效变量键
     * @param candidate 候选字符串
     * @return 是否有效
     */
    private boolean isValidVariableKey(String candidate) {
        if (StringUtils.isBlank(candidate)) return false;
        if (UEL_KEYWORDS.contains(candidate)) return false;
        return VALID_VAR_PATTERN.matcher(candidate).matches();
    }

    /**
     * 提取根变量（去除属性访问和数组索引）
     * @param variable 完整变量表达式
     * @return 根变量名
     */
    private String extractRootVariable(String variable) {
        // 处理属性访问：user.name -> user
        int dotIndex = variable.indexOf('.');
        if (dotIndex > 0) {
            return variable.substring(0, dotIndex);
        }
        
        // 处理数组访问：items[0] -> items
        int bracketIndex = variable.indexOf('[');
        if (bracketIndex > 0) {
            return variable.substring(0, bracketIndex);
        }
        
        // 处理方法调用：user.getName() -> user
        int parenIndex = variable.indexOf('(');
        if (parenIndex > 0) {
            return variable.substring(0, parenIndex);
        }
        
        return variable;
    }

    /**
     * 获取网关的所有出线
     */
    private List<SequenceFlow> getGatewayOutgoingFlows(String processDefinitionId, String gatewayId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        FlowElement element = bpmnModel.getFlowElement(gatewayId);
        
        if (!(element instanceof Gateway)) {
            throw new IllegalArgumentException("ID 为 " + gatewayId + " 的元素不是网关");
        }
        
        return ((Gateway) element).getOutgoingFlows();
    }
}